package main

import (
	"context"
	"fmt"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"syscall"
)

func main() {

	var (
		g = errgroup.Group{}
		stop = make(chan struct{})
		stopped = false  // 是否已发送stop命令
		stopSynch = sync.Mutex{} // 因为需要在signal监听里发送stop命令，多线程读写，需要加锁
	)

	g.Go(func() error {

		// 两个server启动和stopSynch感觉应该封装一下，暂时没处理
		err := serverMain(stop)
		if err != nil {
			err = errors.Wrap(err,"Main server end")
		}
		fmt.Printf("[服务终止]: %v\n", err)
		stopSynch.Lock()
		if !stopped {
			stopped = true
			close(stop)
		}
		stopSynch.Unlock()

		if !errors.Is(err, http.ErrServerClosed) {
			// 非正常关闭则返回异常报错
			return err
		}

		return nil

	})

	g.Go(func() error {
		err := serverDebug(stop);
		if err != nil {
			err = errors.Wrap(err,"Debug server end")
		}
		fmt.Printf("[服务终止]: %v\n", err)
		stopSynch.Lock()
		if !stopped {
			stopped = true
			close(stop)
		}
		stopSynch.Unlock()

		if !errors.Is(err, http.ErrServerClosed) {
			// 非正常关闭则返回异常报错
			return err
		}

		return nil
	})

	// 注册接收的信号：ctrl+c, 程序退出
	exitSigns := make(chan os.Signal, 1)
	signal.Notify(exitSigns, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		sig := <-exitSigns
		fmt.Println("收到命令:", sig)
		stopSynch.Lock()
		if !stopped {
			stopped = true
			close(stop)
		}
		stopSynch.Unlock()

	}()

	// 当所有的server都终止时，才会触发g.Wait(), 这时表示系统可以正常关闭了
	if err := g.Wait(); err != nil {
		fmt.Printf("所有服务已停止，收到异常：%+v\n", err)
	} else {
		fmt.Printf("所有服务已停止，未收到异常")
	}

}

func server(name string, addr string, handler http.Handler, stop <-chan struct{}) error {
	s := http.Server{
		Addr: addr,
		Handler: handler,
	}
	go func() {
		<-stop   // 收到停止指令的时候
		fmt.Println(name, "即将停止")
		s.Shutdown(context.Background())
	}()

	fmt.Println(name, "start to listen on", addr)
	return s.ListenAndServe()
}

func serverMain(stop <-chan struct{}) error {
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		writer.Write([]byte("I am main server"))
	})
	return server("main",":8080", mux, stop)
}

func serverDebug(stop <-chan struct{}) error {
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		writer.Write([]byte("I am server for debug part"))
	})
	return server("debug",":8081", mux, stop)
}

